﻿using System.Collections;
using System.Collections.Generic;
using System.Security.AccessControl;
using System.Xml.Serialization;
using UnityEngine;

public class ActorController : MonoBehaviour {

	public GameObject model;
	public IUserInput PI;
	public CameraController cameracon;

	public float walkSpeed;
	public float runMultiplier;
	public float jumpVelocity;
	public float rollVelocity;
	public float jabMultiplier;
	public float attack1hAMultiplier;
	public bool trackDirection;

	[Header("===Friction Setting===")]
	public PhysicMaterial frictionOne;
	public PhysicMaterial frictionZero;

	private Animator anim;
	private Rigidbody rigid;
	private Vector3 planarVec;
	private Vector3 thrustVec;
	private bool canAttack;
	private CapsuleCollider col;	
	private float lerpTarget;
	private Vector3 deltaPos;

	private bool lockPlanar = false;

	void Awake()
	{
		anim = model.GetComponent<Animator>();
		rigid = GetComponent<Rigidbody>();
		col = GetComponent<CapsuleCollider>();
		IUserInput[] Inputs = GetComponents<IUserInput>();
		foreach (var input in Inputs)
		{
			if(input.enabled == true)
			{
				PI = input;
			}
		}
	}
	void Update () {

		float targetRunMulti = ((PI.run) ? 2.0f : 1.0f);
		
		anim.SetBool("Defence", PI.defence);
		if (PI.lockon)
		{
			cameracon.LockUnLock();
		}
		if(cameracon.lockState == false)
		{
			anim.SetFloat("Forward", PI.Dmag * Mathf.Lerp(anim.GetFloat("Forward"), targetRunMulti, 0.5f));
			anim.SetFloat("Right", 0);
		}
		else
		{
			Vector3 localDVec = transform.InverseTransformVector(PI.Dvec);
			anim.SetFloat("Forward", localDVec.z * targetRunMulti);
			anim.SetFloat("Right", localDVec.x * targetRunMulti);
		}
		if (rigid.velocity.magnitude > 1.0f)
		{
			anim.SetTrigger("Roll");
		}
		if(PI.jump == true)
		{
			anim.SetTrigger("Jump");
			canAttack = false;
		}
		if(PI.attack == true && CheckState("Ground") && canAttack)
		{
			anim.SetTrigger("Attack");
		}
		if (cameracon.lockState == false)
		{
			if (PI.Dmag > 0.01f)
			{
				Vector3 targetForward = Vector3.Slerp(model.transform.forward, PI.Dvec, 0.25f);
				model.transform.forward = targetForward;
			}
			if (lockPlanar == false)
			{
				planarVec = PI.Dmag * model.transform.forward * walkSpeed * ((PI.run) ? runMultiplier : 1.0f);
			}
		}
		else
		{
			if(trackDirection == false)
			{
				model.transform.forward = transform.forward;
			}
			else
			{
				model.transform.forward = planarVec.normalized;
			}
			planarVec = PI.Dvec * walkSpeed * ((PI.run) ? runMultiplier : 1.0f);
		}
	}
	void FixedUpdate()
	{
		rigid.position += deltaPos;
		rigid.velocity = new Vector3(planarVec.x, rigid.velocity.y, planarVec.z) + thrustVec;
		thrustVec = Vector3.zero;
		deltaPos = Vector3.zero;
	}

	private bool CheckState(string stateName, string layerName = "Base Layer")
	{
		return anim.GetCurrentAnimatorStateInfo(anim.GetLayerIndex(layerName)).IsName(stateName);
	}
	
	///
	/// Message processing block
	///

	public void OnJumpEnter()
	{
		PI.inputEnable = false;
		lockPlanar = true;
		thrustVec = new Vector3(0, jumpVelocity, 0);
		trackDirection = true;
	}
	public void IsGround()
	{
		anim.SetBool("isGround",true);
	}
	public void IsNotGround()
	{
		anim.SetBool("isGround", false);
	}
	public void OnGroundEnter()
	{
		PI.inputEnable = true;
		lockPlanar = false;
		canAttack = true;
		col.material = frictionOne;
		trackDirection = false;
	}
	public void OnGroundExit()
	{
		col.material = frictionZero;
	}
	public void OnFallEnter()
	{
		PI.inputEnable = false;
		lockPlanar = true;
	}
	public void OnRollEnter()
	{
		PI.inputEnable = false;
		lockPlanar = true;
		thrustVec = new Vector3(0, rollVelocity, 0);
		trackDirection = true;
	}
	public void OnJabEnter()
	{
		PI.inputEnable = false;
		lockPlanar = true;
	}
	public void OnJabUpdate()
	{
		thrustVec = model.transform.forward * anim.GetFloat("jabVelocity") * jabMultiplier;
	}
	public void OnAttackIdleEnter()
	{
		PI.inputEnable = true;
		lockPlanar = false;
		lerpTarget = 0f;
	}
	public void OnAttackIdleUpdate()
	{
		anim.SetLayerWeight(anim.GetLayerIndex("Attack"), Mathf.Lerp(anim.GetLayerWeight(anim.GetLayerIndex("Attack")), lerpTarget, 0.1f));
	}
	public void OnAttack1hAEnter()
	{
		PI.inputEnable = false;
		lerpTarget = 1.0f;
	}
	public void OnAttack1hAUpdate()
	{
		thrustVec = model.transform.forward * anim.GetFloat("Attack1hAVelocity") * attack1hAMultiplier;
		anim.SetLayerWeight(anim.GetLayerIndex("Attack"), Mathf.Lerp(anim.GetLayerWeight(anim.GetLayerIndex("Attack")), lerpTarget, 0.2f));
	}
	public void OnUpdateRM(object _deltaPos)
	{
		if(CheckState("attack1hA", "Attack")|| CheckState("attack1hB", "Attack")|| CheckState("attack1hC", "Attack"))
		{
			deltaPos += (0.8f*deltaPos + 0.2f*(Vector3)_deltaPos)/1.0f;
		}
	}
	public void OnDefenceIdleEnter()
	{
		lerpTarget = 0f;
	}
	public void OnDefenceIdleUpdate()
	{
		anim.SetLayerWeight(anim.GetLayerIndex("Defence"), Mathf.Lerp(anim.GetLayerWeight(anim.GetLayerIndex("Defence")), lerpTarget, 0.1f));
	}
	public void OnDefenceEnter()
	{
		lerpTarget = 1.0f;
	}
	public void OnDefenceUpdate()
	{
		anim.SetLayerWeight(anim.GetLayerIndex("Defence"), Mathf.Lerp(anim.GetLayerWeight(anim.GetLayerIndex("Defence")), lerpTarget, 0.2f));
	}
}
